﻿using AutoMapper;
using Benefactor.Models.DtoModels;
using Benefactor.Services.Repositories;
using Bigway.Common.Extensions;
using Bigway.Common.Models.DtoModels;
using Bigway.Common.Services.Repositories;
using Microsoft.AspNetCore.Mvc;
using IAppConfig = Benefactor.Services.IAppConfig;

namespace Benefactor.Controllers;

using static Errors;

[ApiController]
[Route("api/voucher")]
public class VoucherController(
    IVoucherRepository voucherRepository,
    IIssuedBenefitsCardRepository issuedBenefitsCardRepository,
    ISoftwareSystemRepository softwareSystemRepository,
    IMapper mapper,
    IAppConfig appConfig,
    ILogger<VoucherController> logger): ControllerBase
{
    public IIssuedBenefitsCardRepository IssuedBenefitsCardRepository { get; } = issuedBenefitsCardRepository;

    [HttpPost]
    public async Task<NoDataResponseDto> UseAsync(
        [FromQuery(Name = "api_key")] string apiKey,
        [FromBody] UseVoucherRequestDto request,
        CancellationToken token = default
    )
    {
        var voucherId = request.VoucherId;
        var consumeCode = request.ConsumeCode;
        logger.LogInformation("Using voucher for system {SystemId} and voucher {VoucherId}",
            request.SystemId,
            voucherId);
        if (apiKey != appConfig.ApiKey)
            return Unauthorized<NoDataResponseDto>();

        var system = await softwareSystemRepository.GetAsync(request.SystemId, token);
        if (system is null)
            return SystemNotFound<NoDataResponseDto>(request.SystemId);

        var voucher = await voucherRepository.GetByIdAsync(voucherId, token);
        if (voucher is null || 
            voucher.MerchantId != request.MerchantId ||
            voucher.ProductId != request.ProductId ||
            voucher.UserId != request.UserId ||
            voucher.IssuedBenefitsCardNo != request.IssuedBenefitsCardNo ||
            voucher.ConsumeCode != consumeCode)
            return VoucherNotFound<NoDataResponseDto>(voucherId);
        else if (voucher.IsDeleted)
            return VoucherDeleted<NoDataResponseDto>(voucherId);
        else if (voucher.IsUsed)
            return VoucherAlreadyUsed<NoDataResponseDto>(voucherId);

        var today = DateOnlyExtensions.Today();
        if (voucher.ValidTo < today)
            return ConsumeCodeExpired<NoDataResponseDto>(consumeCode);
        if (today < voucher.ValidFrom)
            return ConsumeCodeNotActiveYet<NoDataResponseDto>(consumeCode);

        var now = DateTime.UtcNow;
        voucher.IsUsed = true;
        voucher.UseTime = now;

        await voucherRepository.UpdateAsync(voucher, now, token);

        return new NoDataResponseDto();
    }

    [HttpGet]
    public async Task<GetVouchersResponseDto> GetVouchersAsync(
        [FromQuery(Name = "api_key")] string apiKey,
        [FromQuery]GetVouchersRequestDto request,
        CancellationToken token = default
    )
    {
        var systemId = request.system_id;
        var issuedBenefitsCardId = request.issued_benefits_card_id;
        var voucherId = request.voucher_id;
        logger.LogInformation("Getters vouchers for system {SystemId}", systemId);
        if (apiKey != appConfig.ApiKey)
            return Unauthorized<GetVouchersResponseDto>();

        var system = await softwareSystemRepository.GetAsync(systemId, token);
        if (system is null)
            return SystemNotFound<GetVouchersResponseDto>(systemId);

        var vouchers = await voucherRepository.GetAllAsync(
            query =>
            {
                query = query.Where(x => x.SystemId == systemId && !x.IsDeleted);
                if (!string.IsNullOrEmpty(issuedBenefitsCardId))
                    query = query.Where(x => x.IssuedBenefitsCardId == issuedBenefitsCardId);
                if (!string.IsNullOrEmpty(voucherId))
                    query = query.Where(x => x.Id == voucherId);

                query = query.OrderByDescending(x => x.CreateTime);

                return query;
            },
            token);

        return new GetVouchersResponseDto
        {
            Data = vouchers
                .Select(mapper.Map<VoucherInfo>)
        };
    }
}